package com.ps.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ps.constant.MessageConstant;
import com.ps.constant.StatusConstant;
import com.ps.dto.MedicineDTO;
import com.ps.dto.MedicinePageQueryDTO;
import com.ps.entity.Medicine;
import com.ps.entity.MedicineForm;
import com.ps.entity.Setmeal;
import com.ps.entity.SetmealMedicine;
import com.ps.exception.DeletionNotAllowedException;
import com.ps.mapper.MedicineFormMapper;
import com.ps.mapper.MedicineMapper;
import com.ps.mapper.SetmealMapper;
import com.ps.mapper.SetmealMedicineMapper;
import com.ps.result.PageResult;
import com.ps.service.MedicineFormService;
import com.ps.service.MedicineService;
import com.ps.service.SetmealMedicineService;
import com.ps.service.SetmealService;
import com.ps.vo.MedicineVO;
import lombok.Lombok;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static com.ps.constant.SystemConstant.MEDICINE_NOT_EXIST;

@Service
@Slf4j
@RequiredArgsConstructor
public class MedicineServiceImpl extends ServiceImpl<MedicineMapper, Medicine> implements MedicineService {
    private final MedicineMapper medicineMapper;
    private final MedicineFormService medicineFormService;
    private final SetmealMedicineService setmealMedicineService;


    @Override
    @Transactional
    public void saveWithForm(MedicineDTO medicineDTO) {
        Medicine medicine=new Medicine();
        BeanUtils.copyProperties(medicineDTO,medicine);
        //向药品表插入一条数据
        save(medicine);
        //获取insert语句的主键值
        Long medicineId = medicine.getId();
        log.info("获取到id:{}",medicineId);
        List<MedicineForm> forms = medicineDTO.getForms();
        if (forms!=null && !forms.isEmpty()){
            forms.forEach(medicineForm -> {
                medicineForm.setMedicineId(medicineId);
            });
            //向剂型表插入n条数据
            medicineFormService.saveBatch(forms);
        }
    }

    @Override
    public PageResult pageQuery(MedicinePageQueryDTO medicinePageQueryDTO) {
        PageHelper.startPage(medicinePageQueryDTO.getPage(),medicinePageQueryDTO.getPageSize());
        Page<Medicine> page=medicineMapper.medicinepageQuery(medicinePageQueryDTO);
        return new PageResult(page.getTotal(),page.getResult());
    }

    @Override
    @Transactional
    public void deleteBatch(List<Long> ids) {
        // 检查药品是否存在且是否处于可删除状态
        for (Long id : ids) {
            Medicine medicine = query().eq("id", id).one();
            if (medicine == null) {
                throw new IllegalArgumentException(MEDICINE_NOT_EXIST);
            }
            if (medicine.getStatus() == StatusConstant.ENABLE) {
                throw new DeletionNotAllowedException(MessageConstant.Medicine_ON_SALE);
            }
        }
        // 检查药品是否被套餐引用
        LambdaQueryWrapper<SetmealMedicine> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SetmealMedicine::getMedicineId, ids);
        List<SetmealMedicine> setmealMedicines =setmealMedicineService.lambdaQuery()
                .in(SetmealMedicine::getMedicineId, ids).list();
        if (!setmealMedicines.isEmpty()) {
            throw new DeletionNotAllowedException(MessageConstant.Medicine_BE_RELATED_BY_SETMEAL);
        }
        // 删除药品及其相关剂型信息
        removeByIds(ids);
        medicineFormService.removeByIds(ids);
    }

    @Override
    public MedicineVO getByIdwithForm(Long id) {
        Medicine medicine=query().eq("id",id).one();
        List<MedicineForm> medicineForms=medicineFormService
                .query().eq("medicine_id",id).list();
        MedicineVO medicineVO=new MedicineVO();
        BeanUtils.copyProperties(medicine,medicineVO);
        medicineVO.setForms(medicineForms);
        return medicineVO;
    }

    @Override
    @Transactional
    public void updateWithForm(MedicineDTO medicineDTO) {
        //创建Medicine对象
        Medicine medicine=new Medicine();
        //将MedicineDTO中的属性值复制到Medicine对象中
        BeanUtils.copyProperties(medicineDTO,medicine);
        //更新Medicine表中的数据
        lambdaUpdate().eq(Medicine::getId, medicine.getId())
                        .update(medicine);
        //根据MedicineDTO中的id删除MedicineForm表中的数据
        medicineFormService.removeById(medicineDTO.getId());
        //获取MedicineDTO中的剂型列表
        List<MedicineForm> forms = medicineDTO.getForms();
        //如果剂型列表不为空且长度大于0
        if (forms!=null && !forms.isEmpty()){
            //遍历剂型列表
            forms.forEach(medicineForm -> {
                //设置MedicineForm中的MedicineId为MedicineDTO中的id
                medicineForm.setMedicineId(medicineDTO.getId());
            });
            //向剂型表插入n条数据
            medicineFormService.saveBatch(forms);
        }
    }

    @Override
    public List<Medicine> list(Long categoryId) {
        // 创建Medicine对象，设置categoryId和status属性
        Medicine medicine = Medicine.builder()
                .categoryId(categoryId)
                .status(StatusConstant.ENABLE)
                .build();
        return lambdaQuery().eq(Medicine::getCategoryId, medicine.getCategoryId())
                .eq(Medicine::getStatus, medicine.getStatus())
                .orderByDesc(Medicine::getCreateTime)
                .list();

    }
    public List<MedicineVO> listWithForm(Medicine medicine) {
        List<Medicine> medicineList = lambdaQuery()
                .like(StringUtils.hasText(medicine.getName()), Medicine::getName, medicine.getName())
                .eq(medicine.getCategoryId() != null, Medicine::getCategoryId, medicine.getCategoryId())
                .eq(medicine.getStatus() != null, Medicine::getStatus, medicine.getStatus())
                .orderByDesc(Medicine::getCreateTime)
                .list();

        if (medicineList.isEmpty()) {
            return new ArrayList<>();
        }

        // 批量查询所有药品的剂型（优化 N + 1 问题）
        List<Long> medicineIds = medicineList.stream()
                .map(Medicine::getId)
                .collect(Collectors.toList());

        List<MedicineForm> allMedicineForms = medicineFormService.lambdaQuery()
                .in(MedicineForm::getMedicineId, medicineIds)
                .list();

        // 按 medicineId 分组剂型
        Map<Long, List<MedicineForm>> medicineFormMap = allMedicineForms.stream()
                .collect(Collectors.groupingBy(MedicineForm::getMedicineId));

        List<MedicineVO> medicineVOList = new ArrayList<>();
        for (Medicine medicineItem : medicineList) {
            MedicineVO medicineVO = new MedicineVO();
            BeanUtils.copyProperties(medicineItem, medicineVO);
            // 从分组中获取对应剂型（避免循环查询）
            medicineVO.setForms(medicineFormMap.getOrDefault(medicineItem.getId(), new ArrayList<>()));
            medicineVOList.add(medicineVO);
        }
        return medicineVOList;
    }

    @Transactional
    @Override
    public void starOrStop(Integer status, Long id) {
        update().set("status", status)
                .eq("id", id)
                .update();
        // 如果是停售操作，还需将包含当前药品的药品组合也停售
        if (status == StatusConstant.DISABLE) {
            // 查询包含当前药品的所有药品组合ID
            List<Long> setmealIds = setmealMedicineService.lambdaQuery()
                    .select(SetmealMedicine::getSetmealId)
                    .in(SetmealMedicine::getMedicineId, id)
                    .list()
                    .stream()
                    .map(SetmealMedicine::getSetmealId)
                    .distinct()//去重
                    .collect(Collectors.toList());

            // 更新这些药品组合的状态为停售
            if (!setmealIds.isEmpty()) {
                lambdaUpdate().set(Medicine::getStatus, StatusConstant.DISABLE)
                        .in(Medicine::getId, setmealIds)
                        .update();
                }
            }
        }
    }
